
#ifndef RMathHelper_h
#define RMathHelper_h

#include <System/Object.h>
#include <System/Math.h>

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
			/// <summary>
			/// Contains commonly used precalculated values and mathematical operations.
			/// </summary>
			class MathHelper sealed
			{
				private: MathHelper();

    			/// <summary>
				/// Represents the mathematical constant e(2.71828175).
				/// </summary>
				public: static const float E;
        
				/// <summary>
				/// Represents the log base ten of e(0.4342945f).
				/// </summary>
				public: static const float Log10E;
        
				/// <summary>
				/// Represents the log base two of e(1.442695f).
				/// </summary>
				public: static const float Log2E;
        
				/// <summary>
				/// Represents the value of pi(3.14159274).
				/// </summary>
				public: static const float Pi;
        
				/// <summary>
				/// Represents the value of pi divided by two(1.57079637).
				/// </summary>
				public: static const float PiOver2;
        
				/// <summary>
				/// Represents the value of pi divided by four(0.7853982).
				/// </summary>
				public: static const float PiOver4;
        
				/// <summary>
				/// Represents the value of pi times two(6.28318548).
				/// </summary>
				public: static const float TwoPi;
        
				/// <summary>
				/// Returns the Cartesian coordinate for one axis of a point that is defined by a given triangle and two normalized barycentric (areal) coordinates.
				/// </summary>
				/// <param name="value1">The coordinate on one axis of vertex 1 of the defining triangle.</param>
				/// <param name="value2">The coordinate on the same axis of vertex 2 of the defining triangle.</param>
				/// <param name="value3">The coordinate on the same axis of vertex 3 of the defining triangle.</param>
				/// <param name="amount1">The normalized barycentric (areal) coordinate b2, equal to the weighting factor for vertex 2, the coordinate of which is specified in value2.</param>
				/// <param name="amount2">The normalized barycentric (areal) coordinate b3, equal to the weighting factor for vertex 3, the coordinate of which is specified in value3.</param>
				/// <returns>Cartesian coordinate of the specified point with respect to the axis being used.</returns>
				public: static float Barycentric(float value1, float value2, float value3, float amount1, float amount2);

				/// <summary>
				/// Performs a Catmull-Rom interpolation using the specified positions.
				/// </summary>
				/// <param name="value1">The first position in the interpolation.</param>
				/// <param name="value2">The second position in the interpolation.</param>
				/// <param name="value3">The third position in the interpolation.</param>
				/// <param name="value4">The fourth position in the interpolation.</param>
				/// <param name="amount">Weighting factor.</param>
				/// <returns>A position that is the result of the Catmull-Rom interpolation.</returns>
				public: static float CatmullRom(float value1, float value2, float value3, float value4, float amount);

 				/// <summary>
				/// Restricts a value to be within a specified range.
				/// </summary>
				/// <param name="value">The value to clamp.</param>
				/// <param name="min">The minimum value. If <c>value</c> is less than <c>min</c>, <c>min</c> will be returned.</param>
				/// <param name="max">The maximum value. If <c>value</c> is greater than <c>max</c>, <c>max</c> will be returned.</param>
				/// <returns>The clamped value.</returns>
				public: static float ClampF(float value, float min, float max);
        
				/// <summary>
				/// Restricts a value to be within a specified range.
				/// </summary>
				/// <param name="value">The value to clamp.</param>
				/// <param name="min">The minimum value. If <c>value</c> is less than <c>min</c>, <c>min</c> will be returned.</param>
				/// <param name="max">The maximum value. If <c>value</c> is greater than <c>max</c>, <c>max</c> will be returned.</param>
				/// <returns>The clamped value.</returns>
				public: static int Clamp(int value, int min, int max);
        
				/// <summary>
				/// Calculates the absolute value of the difference of two values.
				/// </summary>
				/// <param name="value1">Source value.</param>
				/// <param name="value2">Source value.</param>
				/// <returns>Distance between the two values.</returns>
				public: static float Distance(float value1, float value2);
        
				/// <summary>
				/// Performs a Hermite spline interpolation.
				/// </summary>
				/// <param name="value1">Source position.</param>
				/// <param name="tangent1">Source tangent.</param>
				/// <param name="value2">Source position.</param>
				/// <param name="tangent2">Source tangent.</param>
				/// <param name="amount">Weighting factor.</param>
				/// <returns>The result of the Hermite spline interpolation.</returns>
				public: static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount);
        
				/// <summary>
				/// Linearly interpolates between two values.
				/// </summary>
				/// <param name="value1">Source value.</param>
				/// <param name="value2">Source value.</param>
				/// <param name="amount">Value between 0 and 1 indicating the weight of value2.</param>
				/// <returns>Interpolated value.</returns> 
				/// <remarks>This method performs the linear interpolation based on the following formula.
				/// <c>value1 + (value2 - value1) * amount</c>
				/// Passing amount a value of 0 will cause value1 to be returned, a value of 1 will cause value2 to be returned.
				/// </remarks>
				public: static float Lerp(float value1, float value2, float amount);

				/// <summary>
				/// Returns the greater of two values.
				/// </summary>
				/// <param name="value1">Source value.</param>
				/// <param name="value2">Source value.</param>
				/// <returns>The greater value.</returns>
				public: static float Max(float value1, float value2);
        
				/// <summary>
				/// Returns the lesser of two values.
				/// </summary>
				/// <param name="value1">Source value.</param>
				/// <param name="value2">Source value.</param>
				/// <returns>The lesser value.</returns>
				public: static float Min(float value1, float value2);
        
				/// <summary>
				/// Interpolates between two values using a cubic equation.
				/// </summary>
				/// <param name="value1">Source value.</param>
				/// <param name="value2">Source value.</param>
				/// <param name="amount">Weighting value.</param>
				/// <returns>Interpolated value.</returns>
				public: static float SmoothStep(float value1, float value2, float amount);
        
				/// <summary>
				/// Converts radians to degrees.
				/// </summary>
				/// <param name="radians">The angle in radians.</param>
				/// <returns>The angle in degrees.</returns>
				/// <remarks>
				/// This method uses double precission internally,
				/// though it returns single float
				/// Factor = 180 / pi
				/// </remarks>
				public: static float ToDegrees(float radians);
        
				/// <summary>
				/// Converts degrees to radians.
				/// </summary>
				/// <param name="radians">The angle in degrees.</param>
				/// <returns>The angle in radians.</returns>
				/// <remarks>
				/// This method uses double precission internally,
				/// though it returns single float
				/// Factor = pi / 180
				/// </remarks>
				public: static float ToRadians(float degrees);
	 
				/// <summary>
				/// Reduces a given angle to a value between π and -π.
				/// </summary>
				/// <param name="angle">The angle to reduce, in radians.</param>
				/// <returns>The new angle, in radians.</returns>
				public: static float WrapAngle(float angle);

 				/// <summary>
				/// Determines if value is powered by two.
				/// </summary>
				/// <param name="value">A value.</param>
				/// <returns><c>true</c> if <c>value</c> is powered by two; otherwise <c>false</c>.</returns>
				public: static bool IsPowerOfTwo(int value);
			};
		}
	}
}

#endif